#1.导入第三方包
import os
import gc
import math

import pandas as pd
import numpy as np

import lightgbm as lgb
import xgboost as xgb

from catboost import CatBoostRegressor
from sklearn.linear_model import SGDRegressor, LinearRegression, Ridge
from sklearn.preprocessing import MinMaxScaler


from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.metrics import log_loss
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder

from tqdm import tqdm
import matplotlib.pyplot as plt
import time
import warnings
warnings.filterwarnings('ignore')

#2.读取数据和查看数据
train = pd.read_csv(r'E:\bbbbbcccccccc\pythonProject\数据集\train.csv')
test = pd.read_csv(r'E:\bbbbbcccccccc\pythonProject\数据集\testA.csv')
train.head()


#2.读取数据和查看数据
test.head()


# 3.1数据预处理
def reduce_mem_usage(df):
    start_mem = df.memory_usage().sum() / 1024 ** 2       #numpy中的内存优化
    print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))    #在string文件中    格式化参数用的

    for col in df.columns:
        col_type = df[col].dtype

        if col_type != object:
            c_min = df[col].min()
            c_max = df[col].max()
            if str(col_type)[:3] == 'int':
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                    df[col] = df[col].astype(np.float32)
                else:
                    df[col] = df[col].astype(np.float64)
        else:
            df[col] = df[col].astype('category')

    end_mem = df.memory_usage().sum() / 1024 ** 2
    print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
    print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))

    return df

#3.2 简单预处理
train_list = []

for items in train.values:
    train_list.append([items[0]] + [float(i) for i in items[1].split(',')] + [items[2]])

train = pd.DataFrame(np.array(train_list))
train.columns = ['id'] + ['s_'+str(i) for i in range(len(train_list[0])-2)] + ['label']
train = reduce_mem_usage(train)

test_list=[]
for items in test.values:
    test_list.append([items[0]] + [float(i) for i in items[1].split(',')])

test = pd.DataFrame(np.array(test_list))
test.columns = ['id'] + ['s_'+str(i) for i in range(len(test_list[0])-1)]
test = reduce_mem_usage(test)

print(train.head())
print(test.head())

#4. 训练数据/测试数据准备
x_train = train.drop(['id','label'], axis=1)
y_train = train['label']
x_test=test.drop(['id'], axis=1)

#5.1模型训练
def abs_sum(y_pre,y_tru):    #prediction             绝对值求和
    y_pre=np.array(y_pre)
    y_tru=np.array(y_tru)
    loss=sum(sum(abs(y_pre-y_tru)))
    return loss


# 5.2模型训练
def cv_model(clf, train_x, train_y, test_x, clf_name):
    folds = 5
    seed = 2021                                                          #random_state同一个数字保证每次循环都是分成同样的份。
    kf = KFold(n_splits=folds, shuffle=True, random_state=seed)         #讲训练集分成n_splits份   shuffle表示是否打乱数据的顺序 ，bool 类型。
    test = np.zeros((test_x.shape[0], 4))                #返回来一个给定形状和类型的用0填充的数组
                                                        # order:可选参数，c代表与c语言类似，行优先；F代表列优先

    cv_scores = []
    onehot_encoder = OneHotEncoder(sparse=False)     #主要是采用N位状态寄存器来对N个状态进行编码
    for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
        print('************************************ {} ************************************'.format(str(i + 1)))
        trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], \
                                     train_y[valid_index]

                                                                       #enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列，同时列出数据和数据下标
        if clf_name == "lgb":
            train_matrix = clf.Dataset(trn_x, label=trn_y)
            valid_matrix = clf.Dataset(val_x, label=val_y)

            params = {
                'boosting_type': 'gbdt',    #梯度提升决策树
                'objective': 'multiclass',
                'num_class': 4,
                'num_leaves': 2 ** 5,      #每棵树的叶子数目
                'feature_fraction': 0.8,
                'bagging_fraction': 0.8,     #样本采集比率
                'bagging_freq': 4,
                'learning_rate': 0.1,     #学习率
                'seed': seed,
                'nthread': 28,
                'n_jobs': 24,
                'verbose': -1,
            }
            model = clf.train(params,
                              train_set=train_matrix,
                              valid_sets=valid_matrix,
                              num_boost_round=2000,             #控制迭代次数
                              verbose_eval=100,
                              early_stopping_rounds=200)
            val_pred = model.predict(val_x, num_iteration=model.best_iteration)
            test_pred = model.predict(test_x, num_iteration=model.best_iteration)

        val_y = np.array(val_y).reshape(-1, 1)
        val_y = onehot_encoder.fit_transform(val_y)
        print('预测的概率矩阵为：')
        print(test_pred)
        test += test_pred
        score = abs_sum(val_y, val_pred)
        cv_scores.append(score)
        print(cv_scores)
    print("%s_scotrainre_list:" % clf_name, cv_scores)
    print("%s_score_mean:" % clf_name, np.mean(cv_scores))
    print("%s_score_std:" % clf_name, np.std(cv_scores))
    test = test / kf.n_splits

    return test

#5.3模型训练
def lgb_model(x_train, y_train, x_test):
    lgb_test = cv_model(lgb, x_train, y_train, x_test, "lgb")
    return lgb_test

#5.4模型训练
lgb_test = lgb_model(x_train, y_train, x_test)


